/* 
 * File:   treeview_firewall.cpp
 * Author: ednei
 * 
 * Created on 1 de Julho de 2014, 18:45
 */

#include <valarray>
#include <gtkmm-3.0/gtkmm/treestore.h>

#include "treeview_firewall.h"

REGRAS::REGRAS() {
    this->add(this->linha);
    this->add(this->tabela);
    this->add(this->chain);
    this->add(this->endOrig);
    this->add(this->endDest);
    this->add(this->portaOrigem);
    this->add(this->portaDestino);
    this->add(this->proto);
    this->add(this->alvo);
    this->add(this->opcoes);
    this->add(this->modulo);
    this->add(this->Interface);
}

/*
 * Método construtor que coloca rótulo nas colunas da treeview
 */
treeview_firewall::treeview_firewall() {

    this->bd = new banco(FILE_DB_FIREWALL);

    this->tabela.clear();
    this->chain.clear();

    this->pt_firewall = Gtk::ListStore::create(this->regras);
    this->pt_firewall->clear();

    this->remove_all_columns();

    this->append_column(Glib::ustring("Linha"), this->regras.linha);
    this->append_column(Glib::ustring("Tabela"), this->regras.tabela);
    this->append_column(Glib::ustring("Chain"), this->regras.chain);
    this->append_column(Glib::ustring("Alvo"), this->regras.alvo);
    this->append_column(Glib::ustring("Opções"), this->regras.opcoes);
    this->append_column(Glib::ustring("Endereço de Origem"), this->regras.endOrig);
    this->append_column(Glib::ustring("Porta Origem"), this->regras.portaOrigem);
    this->append_column(Glib::ustring("Endereço de Destino"), this->regras.endDest);
    this->append_column(Glib::ustring("Porta Destino"), this->regras.portaDestino);
    this->append_column(Glib::ustring("Protocolo"), this->regras.proto);
    this->append_column(Glib::ustring("Módulos"), this->regras.modulo);
    this->append_column(Glib::ustring("Interface de Rede"), this->regras.Interface);

    this->treeviewfirewall = Gtk::TreeModelFilter::create(this->pt_firewall);

    /* método que será usado para filtragem das linhas */
    this->set_model(this->treeviewfirewall);

    this->treeviewfirewall->set_visible_func(sigc::mem_fun(*this, &treeview_firewall::order_row_visible));
}

/*
 * Método que verifica se determina linha pode se exibida, "função" de callback
 * iter ponteiro para linha que esta sendo verificada
 * Retorna TRUE a linha pode ser exibida, FALSE caso contrario
 */
bool treeview_firewall::order_row_visible(const Gtk::TreeModel::const_iterator& iter) {

    if (this->tabela.empty() && this->chain.empty()) {
        return true;
    } else if (this->chain.empty() && (!this->tabela.empty())) {
        /* filtra segundo a tabela selecionada */
        Gtk::TreeModel::Row row = *iter;
        string aux;

        aux = row[this->regras.tabela];

        return (aux == this->tabela);
    } else if ((!this->chain.empty()) && (!this->tabela.empty())) {
        /* filtra segundo o conjunto de tabela e chain */
        Gtk::TreeModel::Row row = *iter;
        string aux, aux1;

        aux = row[this->regras.tabela];
        aux1 = row[this->regras.chain];

        return ((aux == this->tabela) && (aux1 == this->chain));
    }
}

/*
 * Método que retorna as "chave" para encontrar os dados da linha seleciona
 * utilizados na alteração e na exclusão
 * Retorna uma string com a linha, tabela e chain
 */
string treeview_firewall::get_regra_selecionada() {
    Glib::RefPtr<Gtk::TreeSelection> Linha_sel = this->get_selection(); //ponteiro para linha selecionada da treeview
    Gtk::TreeModel::iterator iter = Linha_sel->get_selected(); //recebe linha selecionada

    if (Linha_sel->count_selected_rows()) {
        Gtk::TreeModel::Row row = *iter;
        string xml, aux;

        xml.clear();
        aux.clear();

        aux = row[this->regras.linha];
        xml = "<linha>" + aux + "</linha>";

        aux = row[this->regras.tabela];
        xml += "<tabela>" + aux + "</tabela>";

        aux = row[this->regras.chain];
        xml += "<chain>" + aux + "</chain>";

        return xml;
    }

    return "";
}

/*
 * Método que busca regras no banco de dados para
 * exibir na treeview
 */
void treeview_firewall::get_regras_firewall() {
    string sql, aux;
    int cont;
    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    this->pt_firewall->clear();

    sql.clear();

    /*
     * Gera script sql para capturar dados a ser mostrado na treeview
     * aqui já é feita o processo de cocatenar o simbolo de negação
     * sendo necessário apenas capturar os dados e exibir na treeview
     */
    sql = "SELECT rf_linha, t_nome, c_nome, ta_nome,"; //3
    sql += " CASE WHEN ot_nome NOT NULL AND rf_parametros_opcao IS NULL THEN ot_nome"; //4
    sql += " ELSE ot_nome || ' ' || rf_parametros_opcao END,";
    sql += " CASE WHEN rf_not_endereco_origem = 1 THEN '! ' || rf_endereco_origem"; //5
    sql += " ELSE rf_endereco_origem END,";
    sql += " CASE WHEN rf_not_porta_origem = 1 THEN '! ' || rf_porta_origem"; //6
    sql += " ELSE rf_porta_origem END,";

    sql += " CASE WHEN rf_not_endereco_destino = 1 THEN '! ' || rf_endereco_destino"; //7
    sql += " ELSE rf_endereco_destino END,";
    sql += " CASE WHEN rf_not_porta_destino = 1 THEN '! ' || rf_porta_origem"; //8
    sql += " ELSE rf_porta_destino END,";

    sql += " CASE WHEN rf_protocolo IS NULL THEN \'\'"; //9
    sql += " WHEN rf_argumento_protocolo IS NULL AND rf_not_protocolo = \'1\' THEN \'! \' || p_nome";
    sql += " WHEN rf_argumento_protocolo IS NULL AND rf_not_protocolo = \'0\' THEN  \' \' || p_nome";
    sql += " WHEN rf_parametros_protocolo IS NULL AND rf_not_protocolo = \'1\' THEN \'! \' || p_nome || \' \' || op_nome";
    sql += " WHEN rf_parametros_protocolo IS NULL AND rf_not_protocolo = \'0\' THEN p_nome || \' \' || op_nome";
    sql += " WHEN rf_not_protocolo = \'1\' THEN p_nome || \' ! \' || op_nome || \' \' || rf_parametros_protocolo";
    sql += " ELSE p_nome || \' \' || op_nome || \' \' || rf_parametros_protocolo END,";

    sql += " m_nome || ' ' || om_nome || ' ' || rf_parametros_modulo,"; //10
    sql += " CASE WHEN rf_not_interface_rede = 1 THEN rf_interface_rede_saida_entrada || ' - ! ' || rf_interface_rede"; //11
    sql += " ELSE rf_interface_rede_saida_entrada || ' - ' || rf_interface_rede END";
    sql += " FROM regras_firewall";
    sql += " INNER JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id";
    sql += " INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id";
    sql += " INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id";
    sql += " INNER JOIN target ON regras_firewall.rf_target = target.ta_id";
    sql += " LEFT JOIN opcoes_target ON target.ta_id = opcoes_target.ot_target";
    sql += " AND opcoes_target.ot_id = regras_firewall.rf_opcao_target";
    sql += " LEFT JOIN opcoes_modulos ON regras_firewall.rf_modulo = opcoes_modulos.om_id";
    sql += " AND regras_firewall.rf_modulo = opcoes_modulos.om_id";
    sql += " LEFT JOIN modulos ON opcoes_modulos.om_modulo = modulos.m_id";
    sql += " LEFT JOIN protocolos ON regras_firewall.rf_protocolo = protocolos.p_id";
    sql += " LEFT JOIN opcoes_protocolos ON regras_firewall.rf_argumento_protocolo = opcoes_protocolos.op_id";
    sql += " AND protocolos.p_id = opcoes_protocolos.op_protocolo";
    sql += " ORDER BY t_nome, c_nome, rf_linha";

    this->bd->query(sql.c_str());

    if (this->bd->getStatus()) {
        /* atribui os valores BD */
        for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
            valor = *i;

            this->row = (*this->pt_firewall->append());

            for (cont = 0; cont < 12; cont++) {

                aux = valor.at(cont);

                /* coloca os dados nas respectivas celulas da treeview */
                if (cont == 0) {
                    this->row[this->regras.linha] = aux;
                } else if (cont == 1) {
                    this->row[this->regras.tabela] = aux;
                } else if (cont == 2) {
                    this->row[this->regras.chain] = aux;
                } else if (cont == 3) {
                    this->row[this->regras.alvo] = aux;
                } else if (cont == 4) {
                    this->row[this->regras.opcoes] = aux;
                } else if (cont == 5) {
                    this->row[this->regras.endOrig] = aux;
                } else if (cont == 6) {
                    this->row[this->regras.portaOrigem] = aux;
                } else if (cont == 7) {
                    this->row[this->regras.endDest] = aux;
                } else if (cont == 8) {
                    this->row[this->regras.portaDestino] = aux;
                } else if (cont == 9) {
                    this->row[this->regras.proto] = aux;
                } else if (cont == 10) {
                    this->row[this->regras.modulo] = aux;
                } else if (cont == 11) {
                    this->row[this->regras.Interface] = aux;
                }
            }

        }
    }
}

/*
 * Método que busca as politicas padrão
 * no banco de dados para exibir na treeview
 */
void treeview_firewall::get_politica_padrao() {
    string sql, aux;
    int cont;
    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    this->pt_firewall->clear();

    sql = "SELECT tabelas.t_nome, chains.c_nome, target.ta_nome FROM chains_tabela ";
    sql += "INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id ";
    sql += "INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id ";
    sql += "INNER JOIN target ON chains_tabela.ct_politica = target.ta_id";

    this->bd->query(sql.c_str());

    if (this->bd->getStatus()) {
        /* atribui os valores BD */
        for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
            valor = *i;

            this->row = (*this->pt_firewall->append());

            for (cont = 0; cont < 3; cont++) {
                aux = valor.at(cont);

                /* coloca os dados nas respectivas celulas da treeview */
                if (cont == 0) {
                    this->row[this->regras.tabela] = aux;
                } else if (cont == 1) {
                    this->row[this->regras.chain] = aux;
                } else if (cont == 2) {
                    this->row[this->regras.alvo] = aux;
                }
            }
        }
    }

}

/*
 * Método que remove dados da treeview e exibe novamente
 * utilizada ao atualizar, inserir ou remover regras.
 */
void treeview_firewall::recarregar_regras_firewall() {
    this->pt_firewall->clear();
    this->get_regras_firewall();
}

/*
 * Método que é acionado para filtrar dados na treeview.
 * tabela Nome da tabela que deve ser mostrado.
 * chain Nome do chain que deve ser mostrado.
 */
void treeview_firewall::reordena_tabela_chain(string tabela, string chain) {
    this->tabela = tabela;
    this->chain = chain;

    this->treeviewfirewall->refilter();
}

